css: Implement transform-origin
authorMatthias Clasen <mclasen@redhat.com>
Mon, 25 Jan 2021 03:46:01 +0000 (22:46 -0500)
committerMatthias Clasen <mclasen@redhat.com>
Mon, 25 Jan 2021 03:49:08 +0000 (22:49 -0500)
Implement most of transform-origin. We only
handle the xy components currently, which lets
us reuse the position value implementation that
is used for background-position.

docs/reference/gtk/css-properties.md
gtk/gtkcssanimatedstyle.c
gtk/gtkcssstaticstyle.c
gtk/gtkcssstyle.c
gtk/gtkcssstyleprivate.h
gtk/gtkcssstylepropertyimpl.c
gtk/gtkcsstypesprivate.h
gtk/gtkwidget.c

index c44b1308d158dc3b98965b78a02e41169b0c7677..e50f577650658d06f6106a7d6d37998bf34ed1ca 100644 (file)
@@ -164,6 +164,7 @@ done with
 |-gtk-icon-shadow| [Shadow](https://www.w3.org/TR/css-backgrounds-3/#typedef-shadow) or `none` | applied to builtin and application-loaded icons |
 |-gtk-icon-filter| [Filter value list](https://www.w3.org/TR/filter-effects-1/#typedef-filter-value-list) or `none` | applied to builtin and application-loaded icons |
 |transform| [CSS Transforms Level 1](https://www.w3.org/TR/css-transforms-1/#transform-property) | |
+|transform-origin| [CSS Transforms Level 1](https://www.w3.org/TR/css-transforms-1/#transform-origin-property) | CSS allows specifying a z component|
 |min-width| [CSS Box Model Level 3](https://www.w3.org/TR/css3-box/#min-width) | CSS allows percentages |
 |min-height| [CSS Box Model Level 3](https://www.w3.org/TR/css3-box/#min-height) | CSS allows percentages |
 |margin-top| [CSS Box Model Level 3](https://www.w3.org/TR/css3-box/#margin-top) | CSS allows percentages or auto |
index bef4a9028c84ad0e682ab735df40b5344a932027..52e0cabc3be19273c6b7d3eeb72c9b3ebe44e856 100644 (file)
@@ -440,6 +440,10 @@ gtk_css_animated_style_set_animated_value (GtkCssAnimatedStyle *animated,
       unshare_other (animated);
       gtk_css_take_value (&style->other->transform, value);
       break;
+    case GTK_CSS_PROPERTY_TRANSFORM_ORIGIN:
+      unshare_other (animated);
+      gtk_css_take_value (&style->other->transform_origin, value);
+      break;
     case GTK_CSS_PROPERTY_MIN_WIDTH:
       unshare_size (animated);
       gtk_css_take_value (&style->size->min_width, value);
index d4f7bb5fc75c874a7133600e84d9d7cf7a5b9fbe..1c8dd80c56cbfc711b1c90e10f3a5789a3fb585c 100644 (file)
@@ -163,6 +163,7 @@ static const int other_props[] = {
   GTK_CSS_PROPERTY_ICON_TRANSFORM,
   GTK_CSS_PROPERTY_ICON_FILTER,
   GTK_CSS_PROPERTY_TRANSFORM,
+  GTK_CSS_PROPERTY_TRANSFORM_ORIGIN,
   GTK_CSS_PROPERTY_OPACITY,
   GTK_CSS_PROPERTY_FILTER,
 };
@@ -593,6 +594,9 @@ gtk_css_static_style_set_value (GtkCssStaticStyle *sstyle,
     case GTK_CSS_PROPERTY_TRANSFORM:
       gtk_css_take_value (&style->other->transform, value);
       break;
+    case GTK_CSS_PROPERTY_TRANSFORM_ORIGIN:
+      gtk_css_take_value (&style->other->transform_origin, value);
+      break;
     case GTK_CSS_PROPERTY_MIN_WIDTH:
       gtk_css_take_value (&style->size->min_width, value);
       break;
@@ -880,6 +884,7 @@ gtk_css_other_create_initial_values (void)
   values->icon_transform = _gtk_css_initial_value_new_compute (GTK_CSS_PROPERTY_ICON_TRANSFORM, NULL, NULL, NULL);
   values->icon_filter = _gtk_css_initial_value_new_compute (GTK_CSS_PROPERTY_ICON_FILTER, NULL, NULL, NULL);
   values->transform = _gtk_css_initial_value_new_compute (GTK_CSS_PROPERTY_TRANSFORM, NULL, NULL, NULL);
+  values->transform_origin = _gtk_css_initial_value_new_compute (GTK_CSS_PROPERTY_TRANSFORM_ORIGIN, NULL, NULL, NULL);
   values->opacity = _gtk_css_initial_value_new_compute (GTK_CSS_PROPERTY_OPACITY, NULL, NULL, NULL);
   values->filter = _gtk_css_initial_value_new_compute (GTK_CSS_PROPERTY_FILTER, NULL, NULL, NULL);
 
index 106a90ea5ad8ad64d233413511a11d31dc11470e..5d5fc2b44f52ba5e8a8a6eefe732a6ef534eb3ea 100644 (file)
@@ -235,6 +235,8 @@ gtk_css_style_get_value (GtkCssStyle *style,
       return style->size->border_spacing;
     case GTK_CSS_PROPERTY_TRANSFORM:
       return style->other->transform;
+    case GTK_CSS_PROPERTY_TRANSFORM_ORIGIN:
+      return style->other->transform_origin;
     case GTK_CSS_PROPERTY_MIN_WIDTH:
       return style->size->min_width;
     case GTK_CSS_PROPERTY_MIN_HEIGHT:
index 65c8c6f700e4988faf014395ed5353a5094b3afb..27666e9978c9cb5908ee7287a68788648b44e3bd 100644 (file)
@@ -208,6 +208,7 @@ struct _GtkCssOtherValues {
   GtkCssValue *icon_transform;
   GtkCssValue *icon_filter;
   GtkCssValue *transform;
+  GtkCssValue *transform_origin;
   GtkCssValue *opacity;
   GtkCssValue *filter;
 };
index de7f2e3762c687a8f42d2561aa0aa013be03b51d..3eb4ac7c5ce906e546a3e0bc6d05c7b3b4ff94c5 100644 (file)
@@ -790,6 +790,13 @@ background_position_parse (GtkCssStyleProperty *property,
   return _gtk_css_array_value_parse (parser, _gtk_css_position_value_parse);
 }
 
+static GtkCssValue *
+transform_origin_parse (GtkCssStyleProperty *property,
+                        GtkCssParser        *parser)
+{
+  return _gtk_css_position_value_parse (parser);
+}
+
 /*** REGISTRATION ***/
 
 G_STATIC_ASSERT (GTK_CSS_PROPERTY_COLOR == 0);
@@ -1248,6 +1255,13 @@ _gtk_css_style_property_init_properties (void)
                                           GTK_CSS_AFFECTS_TRANSFORM,
                                           transform_value_parse,
                                           _gtk_css_transform_value_new_none ());
+  gtk_css_style_property_register        ("transform-origin",
+                                          GTK_CSS_PROPERTY_TRANSFORM_ORIGIN,
+                                          GTK_STYLE_PROPERTY_ANIMATED,
+                                          GTK_CSS_AFFECTS_TRANSFORM,
+                                          transform_origin_parse,
+                                          _gtk_css_position_value_new (_gtk_css_number_value_new (50, GTK_CSS_PERCENT),
+                                                                       _gtk_css_number_value_new (50, GTK_CSS_PERCENT)));
   gtk_css_style_property_register        ("min-width",
                                           GTK_CSS_PROPERTY_MIN_WIDTH,
                                           GTK_STYLE_PROPERTY_ANIMATED,
index e95e31ac9ca88788441d2ab6043b3cda35256dbf..fe30beaae10a13dcabd280ece35ab9347b4265c4 100644 (file)
@@ -254,6 +254,7 @@ enum { /*< skip >*/
   GTK_CSS_PROPERTY_ICON_FILTER,
   GTK_CSS_PROPERTY_BORDER_SPACING,
   GTK_CSS_PROPERTY_TRANSFORM,
+  GTK_CSS_PROPERTY_TRANSFORM_ORIGIN,
   GTK_CSS_PROPERTY_MIN_WIDTH,
   GTK_CSS_PROPERTY_MIN_HEIGHT,
   GTK_CSS_PROPERTY_TRANSITION_PROPERTY,
index 217293cd231f50509a26b9d557e2a9e3f0d30431..0daeef7a6df2d0151a747aa79a5790f5733ec38c 100644 (file)
@@ -36,6 +36,7 @@
 #include "gtkcssboxesprivate.h"
 #include "gtkcssfiltervalueprivate.h"
 #include "gtkcsstransformvalueprivate.h"
+#include "gtkcsspositionvalueprivate.h"
 #include "gtkcssfontvariationsvalueprivate.h"
 #include "gtkcssnumbervalueprivate.h"
 #include "gtkcssstylepropertyprivate.h"
@@ -3937,12 +3938,17 @@ gtk_widget_allocate (GtkWidget    *widget,
 
   if (css_transform)
     {
+      double origin_x, origin_y;
+
+      origin_x = _gtk_css_position_value_get_x (style->other->transform_origin, adjusted.width);
+      origin_y = _gtk_css_position_value_get_y (style->other->transform_origin, adjusted.height);
+
       transform = gsk_transform_translate (transform, &GRAPHENE_POINT_INIT (adjusted.x, adjusted.y));
       adjusted.x = adjusted.y = 0;
 
-      transform = gsk_transform_translate (transform, &GRAPHENE_POINT_INIT (adjusted.width / 2, adjusted.height / 2));
+      transform = gsk_transform_translate (transform, &GRAPHENE_POINT_INIT (origin_x, origin_y));
       transform = gsk_transform_transform (transform, css_transform);
-      transform = gsk_transform_translate (transform, &GRAPHENE_POINT_INIT (- adjusted.width / 2, - adjusted.height / 2));
+      transform = gsk_transform_translate (transform, &GRAPHENE_POINT_INIT (- origin_x, - origin_y));
 
       gsk_transform_unref (css_transform);
     }